﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media.Animation;
using Emilie.Animation.Simple;

namespace Emilie.Animation
{
    /// <summary>
    /// A collection of preconfigured animations
    /// </summary>
    public static class Presets
    {
        /// <summary>
        /// Begins a staggered slide / fade-in animation, similar to the default EntranceTheme animation
        /// </summary>
        /// <param name="list">List of framework elements to animate</param>
        /// <param name="pauseTime">Time to wait between the slide in of each element in milliseconds. Suggested around 150.</param>
        /// <param name="startOffset">Axis offset to start the animation from. Suggested 40.</param>
        /// <param name="t">Axis to run the translate animation on. Suggested X.</param>
        public static void CollectionEntrance(IEnumerable<FrameworkElement> list, Double endOpacity, TimeSpan pauseTime, Double axisStartOffset, Emilie.Animation.Base.TranslateAxis t)
        {
            GetCollectionEntrance(list, endOpacity, pauseTime, axisStartOffset, t).Begin();
        }

        /// <summary>
        /// Begins a staggered slide / fade-in animation, similar to the default EntranceTheme animation. Preset to 40 pixel offset, 200ms between animations.
        /// </summary>
        /// <param name="list"></param>
        /// <param name="t"></param>
        public static void CollectionEntrance(IEnumerable<FrameworkElement> list)
        {
            CollectionEntrance(list, 1, TimeSpan.FromMilliseconds(75), 40, Base.TranslateAxis.X);
        }

        /// <summary>
        /// Returns a storyboard that creates a staggered slide / fade-in animation, similar to the default EntranceTheme animation
        /// </summary>
        /// <param name="list">List of framework elements to animate</param>
        /// <param name="pauseTime">Time to wait between the slide in of each element in milliseconds. Suggested around 150.</param>
        /// <param name="startOffset">Axis offset to start the animation from. Suggested 40.</param>
        /// <param name="t">Axis to run the translate animation on. Suggested X.</param>
        /// <returns>Completed Storyboard</returns>
        public static Storyboard GetCollectionEntrance(IEnumerable<FrameworkElement> list, Double endOpacity, TimeSpan pauseTime, Double axisStartOffset, Emilie.Animation.Base.TranslateAxis t)
        {
            //var ease = new BackEase { EasingMode = EasingMode.EaseOut, Amplitude = 0 };
            var ease = new QuinticEase();
            TimeSpan duration = TimeSpan.FromMilliseconds(1100);
            TimeSpan fadeDuration = TimeSpan.FromMilliseconds(550);
            Storyboard sb = new Storyboard();
            TimeSpan startTime = TimeSpan.FromMilliseconds(0);
            TimeSpan hideAll = TimeSpan.FromMilliseconds(0);

            foreach (FrameworkElement f in list) f.Opacity = 0;
            foreach (FrameworkElement f in list)
            {
                if (t == Base.TranslateAxis.X) sb.AddDoubleAnimationTranslateX(f, axisStartOffset, 0, startTime, duration, ease);
                else sb.AddDoubleAnimationTranslateY(f, axisStartOffset, 0, startTime, duration, ease);
                sb.AddDoubleAnimationFade(f, 0, endOpacity, startTime, fadeDuration, ease);

                startTime = startTime.Add(pauseTime);
            }

            return sb;
        }

        public static Storyboard EntranceThemeAnimation(IEnumerable<UIElement> targets)
        {
            return SplineEntranceAnimation(targets, 40, TimeSpan.FromMilliseconds(41), TimeSpan.FromMilliseconds(1000));
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="targets"></param>
        /// <param name="staggerOffset">Default: 40</param>
        /// <param name="staggerDuration">Default: 83ms - Time between each animation starting</param>
        /// <param name="slideDuration">Default: 1000ms - Length of slide animation</param>
        /// <returns></returns>
        public static Storyboard SplineEntranceAnimation(IEnumerable<UIElement> targets, Double translationOffset, TimeSpan staggerDuration, TimeSpan slideDuration, Boolean makeVisible = true)
        {
            var sb = new Storyboard();

            var start = TimeSpan.FromSeconds(0);

            foreach (FrameworkElement e in targets)
            {
                e.EnsureCompositeTransform();

                if (makeVisible)
                {
                    var obV = new ObjectAnimationUsingKeyFrames();
                    obV.AddDiscreteObjectKeyFrame(TimeSpan.FromSeconds(0), Visibility.Visible);
                    sb.AddTimeline(obV, e, TargetProperty.Visiblity);
                }
                
                var k = new KeySpline();
                k.SetPoints(0.1, 0.9, 0.2, 1);
                
                var dbX = new DoubleAnimationUsingKeyFrames();
                dbX.AddEasingDoubleKeyFrame(TimeSpan.FromSeconds(0), translationOffset);
                dbX.AddEasingDoubleKeyFrame(start, translationOffset);
                dbX.AddSplineDoubleKeyFrame(start.Add(slideDuration), 0, k);
                sb.AddTimeline(dbX, e, TargetProperty.RenderTransformTranslateX);

                var dbO = new DoubleAnimationUsingKeyFrames();
                dbO.AddEasingDoubleKeyFrame(TimeSpan.FromSeconds(0), 0);
                dbO.AddEasingDoubleKeyFrame(start, 0);
                dbO.AddEasingDoubleKeyFrame(start.Add(TimeSpan.FromSeconds(0.3)), 1);
                sb.AddTimeline(dbO, e, TargetProperty.Opacity);

                // Offset the start of the next animation
                start = start.Add(staggerDuration);
            }

            return sb;
        }

        public static Storyboard SplineEntranceAnimationYAxis(IEnumerable<UIElement> targets, Double translationOffset, TimeSpan staggerDuration, TimeSpan slideDuration, Boolean makeVisible = true)
        {
            var sb = new Storyboard();

            var start = TimeSpan.FromSeconds(0);

            foreach (FrameworkElement e in targets)
            {
                e.EnsureCompositeTransform();

                if (makeVisible)
                {
                    var obV = new ObjectAnimationUsingKeyFrames();
                    obV.AddDiscreteObjectKeyFrame(TimeSpan.FromSeconds(0), Visibility.Visible);
                    sb.AddTimeline(obV, e, TargetProperty.Visiblity);
                }

                var k = new KeySpline();
                k.SetPoints(0.1, 0.9, 0.2, 1);

                var ease = new SineEase { EasingMode = Windows.UI.Xaml.Media.Animation.EasingMode.EaseInOut };

                var dbX = new DoubleAnimationUsingKeyFrames();
                dbX.AddEasingDoubleKeyFrame(TimeSpan.FromSeconds(0), translationOffset);
                dbX.AddEasingDoubleKeyFrame(start, translationOffset);
                dbX.AddSplineDoubleKeyFrame(start.Add(slideDuration), 0, k);
                //dbX.AddEasingDoubleKeyFrame(start.Add(slideDuration), 0, ease);
                sb.AddTimeline(dbX, e, TargetProperty.RenderTransformTranslateY);

                var dbO = new DoubleAnimationUsingKeyFrames();
                //dbO.AddEasingDoubleKeyFrame(TimeSpan.FromSeconds(0), 0);
                dbO.AddEasingDoubleKeyFrame(start, e.Opacity);
                dbO.AddEasingDoubleKeyFrame(start.Add(TimeSpan.FromSeconds(0.3)), 1);
                sb.AddTimeline(dbO, e, TargetProperty.Opacity);

                // Offset the start of the next animation
                start = start.Add(staggerDuration);
            }

            return sb;
        }
    }
}
